﻿using System;
using Nethereum.Hex.HexConvertors.Extensions;
using Xunit;

namespace Nethereum.ABI.UnitTests
{
    public class ElementaryBytesEncodingTests
    {
        [Theory]
        [InlineData("bytes1", "0x01", "0x0100000000000000000000000000000000000000000000000000000000000000")]
        [InlineData("bytes2", "0x0101", "0x0101000000000000000000000000000000000000000000000000000000000000")]
        [InlineData("bytes3", "0x010101", "0x0101010000000000000000000000000000000000000000000000000000000000")]
        [InlineData("bytes4", "0x01010101", "0x0101010100000000000000000000000000000000000000000000000000000000")]
        [InlineData("bytes5", "0x0101010101", "0x0101010101000000000000000000000000000000000000000000000000000000")]
        [InlineData("bytes6", "0x010101010101", "0x0101010101010000000000000000000000000000000000000000000000000000")]
        [InlineData("bytes7", "0x01010101010101", "0x0101010101010100000000000000000000000000000000000000000000000000")]
        [InlineData("bytes8", "0x0101010101010101",
            "0x0101010101010101000000000000000000000000000000000000000000000000")]
        [InlineData("bytes9", "0x010101010101010101",
            "0x0101010101010101010000000000000000000000000000000000000000000000")]
        [InlineData("bytes10", "0x01010101010101010101",
            "0x0101010101010101010100000000000000000000000000000000000000000000")]
        [InlineData("bytes11", "0x0101010101010101010101",
            "0x0101010101010101010101000000000000000000000000000000000000000000")]
        [InlineData("bytes12", "0x010101010101010101010101",
            "0x0101010101010101010101010000000000000000000000000000000000000000")]
        [InlineData("bytes13", "0x01010101010101010101010101",
            "0x0101010101010101010101010100000000000000000000000000000000000000")]
        [InlineData("bytes14", "0x0101010101010101010101010101",
            "0x0101010101010101010101010101000000000000000000000000000000000000")]
        [InlineData("bytes15", "0x010101010101010101010101010101",
            "0x0101010101010101010101010101010000000000000000000000000000000000")]
        [InlineData("bytes16", "0x01010101010101010101010101010101",
            "0x0101010101010101010101010101010100000000000000000000000000000000")]
        [InlineData("bytes17", "0x0101010101010101010101010101010101",
            "0x0101010101010101010101010101010101000000000000000000000000000000")]
        [InlineData("bytes18", "0x010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010000000000000000000000000000")]
        [InlineData("bytes19", "0x01010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010100000000000000000000000000")]
        [InlineData("bytes20", "0x0101010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010101000000000000000000000000")]
        [InlineData("bytes21", "0x010101010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010101010000000000000000000000")]
        [InlineData("bytes22", "0x01010101010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010101010100000000000000000000")]
        [InlineData("bytes23", "0x0101010101010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010101010101000000000000000000")]
        [InlineData("bytes24", "0x010101010101010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010101010101010000000000000000")]
        [InlineData("bytes25", "0x01010101010101010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010101010101010100000000000000")]
        [InlineData("bytes26", "0x0101010101010101010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010101010101010101000000000000")]
        [InlineData("bytes27", "0x010101010101010101010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010101010101010101010000000000")]
        [InlineData("bytes28", "0x01010101010101010101010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010101010101010101010100000000")]
        [InlineData("bytes29", "0x0101010101010101010101010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010101010101010101010101000000")]
        [InlineData("bytes30", "0x010101010101010101010101010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010101010101010101010101010000")]
        [InlineData("bytes31", "0x01010101010101010101010101010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010101010101010101010101010100")]
        [InlineData("bytes32", "0x0101010101010101010101010101010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010101010101010101010101010101")]
        public virtual void ShouldDecode(string typeName, string expected, string hex)
        {
            var bytesType = ABIType.CreateABIType(typeName);
            var result = bytesType.Decode<byte[]>(hex);
            Assert.Equal(expected, result.ToHex(true));
        }

        [Theory]
        [InlineData("bytes1", "0x01", "0x0100000000000000000000000000000000000000000000000000000000000000")]
        [InlineData("bytes2", "0x0101", "0x0101000000000000000000000000000000000000000000000000000000000000")]
        [InlineData("bytes3", "0x010101", "0x0101010000000000000000000000000000000000000000000000000000000000")]
        [InlineData("bytes4", "0x01010101", "0x0101010100000000000000000000000000000000000000000000000000000000")]
        [InlineData("bytes5", "0x0101010101", "0x0101010101000000000000000000000000000000000000000000000000000000")]
        [InlineData("bytes6", "0x010101010101", "0x0101010101010000000000000000000000000000000000000000000000000000")]
        [InlineData("bytes7", "0x01010101010101", "0x0101010101010100000000000000000000000000000000000000000000000000")]
        [InlineData("bytes8", "0x0101010101010101",
            "0x0101010101010101000000000000000000000000000000000000000000000000")]
        [InlineData("bytes9", "0x010101010101010101",
            "0x0101010101010101010000000000000000000000000000000000000000000000")]
        [InlineData("bytes10", "0x01010101010101010101",
            "0x0101010101010101010100000000000000000000000000000000000000000000")]
        [InlineData("bytes11", "0x0101010101010101010101",
            "0x0101010101010101010101000000000000000000000000000000000000000000")]
        [InlineData("bytes12", "0x010101010101010101010101",
            "0x0101010101010101010101010000000000000000000000000000000000000000")]
        [InlineData("bytes13", "0x01010101010101010101010101",
            "0x0101010101010101010101010100000000000000000000000000000000000000")]
        [InlineData("bytes14", "0x0101010101010101010101010101",
            "0x0101010101010101010101010101000000000000000000000000000000000000")]
        [InlineData("bytes15", "0x010101010101010101010101010101",
            "0x0101010101010101010101010101010000000000000000000000000000000000")]
        [InlineData("bytes16", "0x01010101010101010101010101010101",
            "0x0101010101010101010101010101010100000000000000000000000000000000")]
        [InlineData("bytes17", "0x0101010101010101010101010101010101",
            "0x0101010101010101010101010101010101000000000000000000000000000000")]
        [InlineData("bytes18", "0x010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010000000000000000000000000000")]
        [InlineData("bytes19", "0x01010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010100000000000000000000000000")]
        [InlineData("bytes20", "0x0101010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010101000000000000000000000000")]
        [InlineData("bytes21", "0x010101010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010101010000000000000000000000")]
        [InlineData("bytes22", "0x01010101010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010101010100000000000000000000")]
        [InlineData("bytes23", "0x0101010101010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010101010101000000000000000000")]
        [InlineData("bytes24", "0x010101010101010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010101010101010000000000000000")]
        [InlineData("bytes25", "0x01010101010101010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010101010101010100000000000000")]
        [InlineData("bytes26", "0x0101010101010101010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010101010101010101000000000000")]
        [InlineData("bytes27", "0x010101010101010101010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010101010101010101010000000000")]
        [InlineData("bytes28", "0x01010101010101010101010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010101010101010101010100000000")]
        [InlineData("bytes29", "0x0101010101010101010101010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010101010101010101010101000000")]
        [InlineData("bytes30", "0x010101010101010101010101010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010101010101010101010101010000")]
        [InlineData("bytes31", "0x01010101010101010101010101010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010101010101010101010101010100")]
        [InlineData("bytes32", "0x0101010101010101010101010101010101010101010101010101010101010101",
            "0x0101010101010101010101010101010101010101010101010101010101010101")]
        public virtual void ShouldEncode(string typeName, string hex, string expected)
        {
            var bytesType = ABIType.CreateABIType(typeName);
            var result = bytesType.Encode(hex.HexToByteArray());
            Assert.Equal(expected, result.ToHex(true));
        }

        [Fact]
        public virtual void ShouldEncodeGuid()
        {
            var bytesType = ABIType.CreateABIType("bytes16");
            var guid = Guid.NewGuid();
            var result = bytesType.Encode(guid);
            Assert.Equal("0x" + guid.ToByteArray().ToHex() + "00000000000000000000000000000000", result.ToHex(true));
        }

        [Fact]
        public virtual void ShouldDecodeGuid()
        {
            var bytesType = ABIType.CreateABIType("bytes16");
            var guid = Guid.NewGuid();
            var encoded = bytesType.Encode(guid);

            var result = bytesType.Decode<Guid>(encoded);
            Assert.Equal(guid, result);
        }
    }
}